import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Esta clase representa a proyectiles.
 * @author Miguel Martinez Aguilar
 * @version 25 de Marzo del 2013
 */
public abstract class Proyectil extends ScrollActor
{
    // Declaracion de variables de instancia
    protected int xi;// es la coordenada (x) inicial del proyectil.
    protected int yi;// es la coordenada (y) inicial del proyectil.
    protected int cont;// es el contador del tiempo.
    protected int e;// es una bandera para ajuste del impacto del proyectil.
    protected double tiempo;// es el tiempo.
    protected double gravedad;// es la gravedad.
    protected double vox;// es la velocidad en (x).
    protected Espacio esp;// es el espacio al que apunta el proyectil.
    protected GreenfootImage[] img;// es un arreglo de imagenes que representan el tamaño del proyectil.
    protected Lanzador lanz;// es el objeto lanzador.

    /**
     * Este es el constructor de proyectil.
     * @param lanz: el lanzador que creo este proyectil.
     * @param xi: la coordenada x inicial de este proyectil en el escenario.
     * @param yi: la coordenada y inicial de este proyectil en el escenario.
     * @param tiempo: el tiempo que durara el proyectil en movimiento.
     * @param gravedad: la gravedad que influira al proyectil en movimiento.
     * @param vox: numero que indica la velocidad del proyectil en ej eje x.
     * @param destino: Es espacio que este proyectil destruira.
     */
    public Proyectil(Lanzador lanz, int xi, int yi, double tiempo, double gravedad, double vox, Espacio destino) 
    {
        this.img = new GreenfootImage[4];
        this.xi = xi;
        this.yi = yi;
        this.tiempo = tiempo;
        this.cont = this.e = 0;
        this.gravedad = gravedad;
        this.vox = vox;
        this.esp = destino;
        this.lanz = lanz;
    }  
    
    /**
     * Este metodo mueve al proyectil hacia su destino.
     */
    public void act() 
    {
        if(cont < tiempo)cont++;
        if(cont < tiempo)this.mueveProyectil();
        else{
            if(e == 0)this.ajustaImpacto();
            if(e == 1)lanz.barcoDestruido(this.destruye());
            this.e++;
        }
    }
    
    /**
     * Este metodo mueve un proyectil hacia su blanco
     */
    public void mueveProyectil()
    {
        int x = (int)vox * cont;
        int y = ((int)gravedad / 2) * (cont * cont);
        this.turnTowards(xi + x,yi + y);
        this.setLocation(xi + x,yi + y);
        this.cambiaImagen(x,y);
    } 
    
    /**
     * Este metodo cambia la imagen de los proyectiles.
     * @param x: coordenada x a evaluar.
     * @param y: coordenada y a evaluar.
     */
    public void cambiaImagen(int x, int y)
    {
        if((yi + y) > (yi + (3*78)))this.setImage(img[3]);
        else {
            if((yi + y) > (yi + (2*78)))this.setImage(img[2]);
            else if((yi + y) > (yi + 78))this.setImage(img[1]);
        }
    } 
    
    /**
     * Este metodo ajusta el impacto del proyectil
     */
    public void ajustaImpacto()
    {
        if(esp.getX() > this.getX() && esp.getY() > this.getY())this.setLocation(esp.getX(),esp.getY());
        else if(esp.getX() < this.getX() && esp.getY() > this.getY())this.setLocation(esp.getX(),esp.getY());
    }
    
    /**
     * Este metodo agrega el efecto de ola y splasch.
     * @param espacio: un espacio en donde se creara el efecto de splash.
     */
    public void splash(Espacio espacio)
    {
        if(espacio != null){
            ScrollWorld escena = super.getWorld();
            Ola ola = new Ola();
            escena.addObject(ola, espacio.getGlobalX(), espacio.getGlobalY());
            ola.CambiaGetGlobalXY(espacio.getGlobalX(), espacio.getGlobalY());
            Greenfoot.playSound("splash.wav");
        }
    }  
    
    /**
     * Este metodo destruye 2 espacios, ya sea en horizontal o vertical. <p>
     * Regresa un boleano.
     * @param vertical: boleano que indica si los espacios a destruir seran en horizontal o vertical.
     * @param espacio: el espacio de referencia para destruir.
     */
    public boolean destruye2(boolean vertical, Espacio espacio)
    {
        boolean val = false;
        boolean val2 = false;
        if(espacio!=null){
            Espacio esp2 = null;
            if(!vertical)esp2 = espacio.hayEspacio(espacio.fila(),espacio.col() - 1);
            if(vertical)esp2 = espacio.hayEspacio(espacio.fila() + 1,espacio.col());
            ScrollWorld escena = super.getWorld();
            this.splash(espacio);
            if(esp2 != null)this.splash(esp2);
            lanz.impacto(true);
            if(espacio.hayBarco() != null){
                val = espacio.impactaBarco();
                lanz.hayBarco(true);
                if(val)val2 = true;
            }
            if(esp2 != null){
                if(esp2.hayBarco() != null){
                    val = esp2.impactaBarco();
                    lanz.hayBarco(true);
                    if(val)val2 = true;
                }
            }
            espacio.quitarDeTablero();
            if(esp2 != null)esp2.quitarDeTablero();
            escena.removeObject(espacio);// con este metodo eliminamos un objeto del mundo
            if(esp2 != null)escena.removeObject(esp2);// con este metodo eliminamos un objeto del mundo
        }
        return val2;
    } 
    
    /**
     * Este metodo permite destruir un Espacio. <p>
     * Regresa un boleano.
     * @param espacio: el espacio a destruir.
     */
    public boolean destruye1(Espacio espacio)
    {
        boolean val = false;
        if(espacio != null){
            ScrollWorld escena = super.getWorld();
            this.splash(espacio);
            lanz.impacto(true);
            if(espacio.hayBarco() != null){
                val = espacio.impactaBarco();
                lanz.hayBarco(true);
            }
            espacio.quitarDeTablero();
            escena.removeObject(espacio);// con este metodo eliminamos un objeto del mundo
        }
        return val;
    }
    
    /**
     * Este metodo abstracto permite destruir Espacios. <p>
     * Regresa un boleano.
     */
    public abstract boolean destruye();
}
